	var states;
	var maxTaskId = 0;					// Max task ID (used to find out next task ID).
	var maxExtraId = 0;					// Max task ID (used to find out next task ID).
	var taskTableId = "taskTable";		// HTML task table ID.
	var partTableId = "excludeTable";
	var extraTableId = "extraTable";
	var partList = new Array();			// Participant List (with extras and without excluded).
	var participantList = new Array();			// Participant List (with extras and without excluded).
	var extraPartList = new Array();	// Participant List (with extras and without excluded).
	var excludeList = new Array();		// Exclude Participants from list.
	var itemPrefix = "task";
	var extraPrefix = "extra";
	var partPrefix = "part";
	
	function showInfo() {
	// function responsible for showing the information about this gadget
	
		alert("This gadget is intended for managing tasks, deadlines, assgiments and progress in projects.");
	}
	
	function openLink(lnk, newWindow) {
	// function reponsible for opening supplied link
	
		if (newWindow) window.open(lnk, 'open_window');
		else window.location.href=lnk;
	}
	
	function loadParticipants() {
	// Function responsible for loading participants
		
		states = wave.getState();
		keys = states.getKeys();

		for (key in keys) {
			if (key && keys[key]) {
				var stt = states.get(keys[key]);
				// Get Extra Participants List
				if (stt && keys[key].indexOf(extraPrefix) == 0) {
					partList[keys[key]] = stt;
					extraPartList[keys[key]] = stt;
				}
				// Get Participants to exclude List
				if (stt && keys[key].indexOf(partPrefix) == 0)
					excludeList[keys[key]] = stt;
			}
		}
		
		var participants = wave.getParticipants();
		if (participants) {
			for (var i = 0; i < participants.length; ++i) {
				partList[participants[i].getId()] = participants[i].getDisplayName();
				participantList[participants[i].getId()] = participants[i].getDisplayName();
			}
		}
		
		// Remove Excluded from List
		for (idx in excludeList) {
			for (key in partList) {
				if (idx == key) partList[idx] = NULL;
			}
		}

		// Update SELECTs with final Participant List
		for (elem in document.elements) {
			if (elem.nodeName == "SELECT" && strEndsWith(elem.id, "assigned")) {
				addSelectOptionsFromArray(elem, partList);
			}
		}
		
		loadParticipantsTable();
		loadExtraTable();
	}
	
	function loadParticipantsTable() {
	// function responsible for loading the participant list in admin mode.
	
		for (part in participantList) {
			if (!document.getElementById(partPrefix + part)) insertPartRow(partTableId, part, false, participantList[part]);

			loadValue(partPrefix, part, "admin");
			loadValue(partPrefix, part, "excluded");
			loadValue(partPrefix, part, "edit");
		}
	} 
	
	function loadExtraTable() {
	// function responsible for loading the participant list in admin mode.
	
		for (part in extraPartList) {
			var partIdStr = part.substr(5, 4);
			var partId = Number(partIdStr);

			if (!document.getElementById(extraPrefix + partIdStr)) insertPartRow(extraTableId, partId, true);
			
			// Update the value of the max partId
			if (partId > maxExtraId) maxExtraId = partId;
			
			loadValue(extraPrefix, partIdStr, "name");
		}
	}
	
	function loadValue(prefix, itemId, itemItem) {
	// function responsible for loading state values 
	
		var itemValue = wave.getState().get(prefix + itemId + itemItem);
		updateValue(prefix, itemId, itemItem, itemValue, true);
	}
	
	function loadTasks() {
	// function responsible for loading all the tasks
	
		states = wave.getState();
		states = wave.getState();
		
		if (!states) return;
		
		var keys = states.getKeys();
		var taskIdList = new Array();
		var found = false;
		for (key in keys) {
			if (keys[key] && keys[key].indexOf("task") == 0) {
				var taskIdStr = keys[key].substr(4, 4);
				var taskId = Number(taskIdStr);

				// Update the value of the max taskId
				if (taskId > maxTaskId) maxTaskId = taskId;
				
				found = false;
				for (tsk in taskIdList)
					if (tsk == taskIdStr) found = true;
				if (!found) {
					taskIdList[taskIdStr] = taskIdStr;
					if (!document.getElementById(itemPrefix + taskIdStr)) insertRow(taskTableId, taskIdStr, false);
				}
			}
		}
		// Iterates all the keys
		for (tsk in taskIdList) {
			for (key in keys) {
				// Check for task__ keys
				if (key && keys[key] && keys[key].indexOf("task" + tsk) == 0) {
					var itm = keys[key].substr(8);
					var elem = document.getElementById(keys[key]);
					if (elem) {
						updateValue(itemPrefix, tsk, itm, states.get(keys[key]), true)
					}
				}
			}
		}
	
	}
	
	function insertTask() {
	// function responsible for inserting a new Task to the list.
	
		maxTaskId = maxTaskId + 1;
		insertRow(taskTableId, maxTaskId, true);
	}

	function insertExtraPart() {
	// function responsible for creating a new row to insert extra participants.
	
		maxExtraId = maxExtraId + 1;
		insertPartRow(extraTableId, maxExtraId, true);
		
	}
	
	function deleteItem(obj, itemStr) {
	// function responsible for deleting a Task from the list.
	
		if (confirm("Are you sure you want to delete this " + itemStr + "?")) {
		
			var row = obj.parentNode.parentNode.parentNode;
			var rowId = row.rowIndex;
			deleteRow(taskTableId, rowId);
			
			states = wave.getState();
			keys = states.getKeys();
			
			for(key in keys) {
				if(keys[key].indexOf(row.id) == 0)
					wave.getState().submitValue(keys[key], null);
			}
		}
	}
	
	function insertRow(tblId, taskId, enableEdit) {
	// function responsible for adding new rows to the tasks table
		
		var nextTaskId = "";
		
		if ((""+taskId).length<4) {
			if (taskId < 10) nextTaskId = "000" + taskId;
			else if (taskId < 100) nextTaskId = "00" + taskId;
			else if (taskId < 1000) nextTaskId = "0" + taskId;
			else nextTaskId = "" + taskId;
		}
		else nextTaskId = "" + taskId;
		
		var itemTaskPrefix = itemPrefix + nextTaskId;
		
		var tblBody = document.getElementById(tblId).tBodies[0];
		var newRow = tblBody.insertRow(-1);
		newRow.id = itemPrefix + nextTaskId;

		// Task Name
		var newCell0 = document.createElement("TH");//newRow.insertCell(0);
		newCell0.innerHTML = '<span id="' + itemTaskPrefix + 'namedesc_span" class="text"><span id="' + itemTaskPrefix + 'name_span">&nbsp;</span><br/>' +
							 '<span id="' + itemTaskPrefix + 'desc_span" class="text_small">&nbsp;</span></span>' + 
							 '<input id="' + itemTaskPrefix + 'name" type="text" onchange="updateValue(\'' + itemPrefix + '\', \'' + nextTaskId + '\', \'name\', this.value);" style="width:100%;"/>' + 
							 '<textarea id="' + itemTaskPrefix + 'desc" onchange="updateValue(\'' + itemPrefix + '\', \'' + nextTaskId + '\', \'desc\', this.value);" style="width:100%;"/>';
		newCell0.scope="row";
		newRow.appendChild(newCell0);

		// Task deadline
		var newCell1 = newRow.insertCell(1);
		newCell1.innerHTML = '<span id="' + itemTaskPrefix + 'deadline_span" class="text_small">&nbsp;</span><input id="' + itemTaskPrefix + 'deadline" type="text" onchange="updateValue(\'' + itemPrefix + '\', \'' + nextTaskId + '\', \'deadline\', this.value);" style="width:100%;"/>';

		// Task assigned to
		var newCell2 = newRow.insertCell(2);
		newCell2.innerHTML = '<span id="' + itemTaskPrefix + 'assigned_span" class="text_small">&nbsp;</span><select id="' + itemTaskPrefix + 'assigned" onchange="updateValue(\'' + itemPrefix + '\', \'' + nextTaskId + '\', \'assigned\', this.options[this.selectedIndex].text);" style="width:100%;"></select>';

		// Task progress
		var newCell3 = newRow.insertCell(3);
		newCell3.innerHTML = '<span id="' + itemTaskPrefix + 'progress_span" class="text_small">&nbsp;</span><input id="' + itemTaskPrefix + 'progress" type="text" onchange="updateValue(\'' + itemPrefix + '\', \'' + nextTaskId + '\', \'progress\', this.value);" style="width:100%;"/>';

		// Task images
		var newCell4 = newRow.insertCell(4);
		newCell4.innerHTML = '<span id="' + itemTaskPrefix + 'editImg" class="image"><img src="http://project-wave-gadgets.googlecode.com/svn/trunk/accept.png" title="Accept Changes" onclick="editEnable(false, \'' + nextTaskId + '\');"/></span> ' +
							 '<span id="' + itemTaskPrefix + 'viewImg" class="image"><img src="http://project-wave-gadgets.googlecode.com/svn/trunk/remove.png" onclick="deleteItem(this, \'task\');" title="Delete task" /> ' +
							                                      '<img src="http://project-wave-gadgets.googlecode.com/svn/trunk/edit.png" title="Edit task" onclick="editEnable(true, \'' + nextTaskId + '\');" /></span>';
		newCell4.width = "1px";
		newCell4.align = "center";
		
		if (enableEdit) editEnable(true, nextTaskId);
		else editEnable(false, nextTaskId);
		
		addSelectOptionsFromArray(document.getElementById(itemTaskPrefix + 'assigned'), partList);
		updateOddRows(tblId);
		if (gadgets && gadgets.window && gadgets.window.adjustHeight) gadgets.window.adjustHeight();
	}
	
	function insertPartRow(tblId, partID, extraBool, displayName) {
	// function responsible for adding new rows to the tasks table
		var prefix = "";
		if (extraBool) prefix = extraPrefix;
		else prefix = partPrefix;

		var nextPartID = "";
		
		if ((""+partID).length<4) {
			if (partID < 10) nextPartID = "000" + partID;
			else if (partID < 100) nextPartID = "00" + partID;
			else if (partID < 1000) nextPartID = "0" + partID;
			else nextPartID = "" + partID;
		}
		else nextPartID = "" + partID;
		
		var tblBody = document.getElementById(tblId).tBodies[0];
		var newRow = tblBody.insertRow(-1);
		newRow.id = prefix + nextPartID;

		// Participant/Extra Participant Name
		var newCell0 = document.createElement("TH");
		if (extraBool) newCell0.innerHTML = '<input id="' + prefix + nextPartID + 'name" type="text" onchange="updateValue(\'' + extraPrefix + '\', \'' + nextPartID + '\', \'name\', this.value, false);" style="width:100%;"/>';
		else newCell0.innerHTML = '<span id="' + prefix + nextPartID + 'name_span">' + displayName + '</span>';
		newCell0.scope="row";
		newRow.appendChild(newCell0);

		if (!extraBool) {
			// Exclude from "assigned to" list
			var newCell1 = newRow.insertCell(1);
			newCell1.innerHTML = '<input id="' + prefix + nextPartID + 'excluded" type="checkbox" onkeypress="updateValue(\'' + partPrefix + '\', \'' + nextPartID + '\', \'excluded\', this.checked, false);" style="width:100%;"/>';

			// Can edit tasks
			var newCell2 = newRow.insertCell(2);
			newCell2.innerHTML = '<input id="' + prefix + nextPartID + 'edit" type="checkbox" onkeypress="updateValue(\'' + partPrefix + '\', \'' + nextPartID + '\', \'edit\', this.checked, false);" style="width:100%;"/>';

			// Has admin rights
			var newCell3 = newRow.insertCell(3);
			newCell3.innerHTML = '<input id="' + prefix + nextPartID + 'admin" type="checkbox" onkeypress="updateValue(\'' + partPrefix + '\', \'' + nextPartID + '\', \'admin\', this.checked, false);" style="width:100%;"/>';
		}
		else {
			// Dummy cell
			var newCell1 = newRow.insertCell(1);
			newCell1.innerHTML = '&nbsp;';
			newCell1.innerHTML = '<span id="' + prefix + nextPartID + 'Img" class="image"><img src="http://project-wave-gadgets.googlecode.com/svn/trunk/remove.png" onclick="deleteItem(this, \'participant\');" title="Delete extra-participant." /></span>';
			newCell1.width = "1px";
			newCell1.align = "center";
		}

		updateOddRows(tblId);
		if (gadgets && gadgets.window && gadgets.window.adjustHeight) gadgets.window.adjustHeight();
	}
	
	function editEnable(toEnable, taskId) {
	// function responsible for enabling/ disabling the editable state
	
		var spanState = '';
		var inputState = '';
	
		if (toEnable) {
			spanState = 'none';
			inputState = 'inherit';
		}
		else {
			spanState = 'inherit';
			inputState = 'none';
		}

		document.getElementById(itemPrefix + taskId + "namedesc_span").style.display = spanState;
		document.getElementById(itemPrefix + taskId + "deadline_span").style.display = spanState;
		document.getElementById(itemPrefix + taskId + "assigned_span").style.display = spanState;
		document.getElementById(itemPrefix + taskId + "progress_span").style.display = spanState;
		document.getElementById(itemPrefix + taskId + "viewImg").style.display = spanState;

		document.getElementById(itemPrefix + taskId + "name").style.display = inputState;
		document.getElementById(itemPrefix + taskId + "desc").style.display = inputState;
		document.getElementById(itemPrefix + taskId + "deadline").style.display = inputState;
		document.getElementById(itemPrefix + taskId + "assigned").style.display = inputState;
		document.getElementById(itemPrefix + taskId + "progress").style.display = inputState;
		document.getElementById(itemPrefix + taskId + "editImg").style.display = inputState;
		if (gadgets && gadgets.window && gadgets.window.adjustHeight) gadgets.window.adjustHeight();
	}
	
	function deleteRow(tblId, index) {
	// function responsible for deleting a table row
	
		if (index && tblId) {
			document.getElementById(tblId).deleteRow(index);
			updateOddRows(tblId);
			if (gadgets && gadgets.window && gadgets.window.adjustHeight) gadgets.window.adjustHeight();
		}
	}
	
	function updateValue(itemPrefix, itemId, itemItem, value, updateBoth) {
	// function responsible for updating values
	
		var elemSpan = document.getElementById(itemPrefix + itemId + itemItem + "_span");
		if (elemSpan) {
			elemSpan.firstChild.nodeValue = value;
		}
		if (updateBoth) {
			var elem = document.getElementById(itemPrefix + itemId + itemItem);
			if (elem) {
				if (elem.nodeName == "INPUT") {
					elem.value = value;
				}
				else if (elem.nodeName == "SELECT") {
					setSelectOption(elem, value);
				}
			}
		}
		else {
			wave.getState().submitValue((itemPrefix + itemId + itemItem), value);
		}
	}
	
	function setSelectOption(selectObj, selectedValue) {
	// Function to make the selectedindex form the pretended Value
	
		for(index = 0; index < selectObj.options.length; index++) {
			if(selectObj.options[index].value == selectedValue)
				//selectObj.selectedIndex = index;
				selectObj.options[index].selected = true;
		}
	}

	function strEndsWith(str, suffix) {
		return str.match(suffix+"$")==suffix;
	}

	function addSelectOptionsFromArray(selectObj, optionArray) {
	// function responsible for adding all the options from an array
		selectObj.options[0] = new Option("", "");
		for (opt in optionArray)
			selectObj.options[selectObj.options.length] = new Option(optionArray[opt], opt);
	}
	
	function updateOddRows(tblId) {
	// function responsible for updating the odd class in the table
	
		var tbl = document.getElementById(tblId);
		if (tbl && tbl.tBodies && tbl.tBodies[0] && tbl.tBodies[0].rows.length>0)
			for (row in tbl.tBodies[0].rows) {
				if (tbl.tBodies[0].rows[row] && tbl.tBodies[0].rows[row].id && tbl.tBodies[0].rows[row].id.indexOf(itemPrefix) == 0) {
					if ((tbl.tBodies[0].rows[row].rowIndex % 2) == 1)
						tbl.tBodies[0].rows[row].className = "odd";
					else tbl.tBodies[0].rows[row].className = "";
				}
			}
	}
	
	function changeMode() {
	// function responsible for switching gadget modes between Admin and TaskManagement
	
		var adminDiv = document.getElementById("adminMode");
		var taskDiv = document.getElementById("taskMode");
		if (taskDiv && adminDiv) {
			if (adminDiv.style.display == "none") {
				if (gadgets && gadgets.window) gadgets.window.setTitle("Task Management");
				adminDiv.style.display = "inherit";
				taskDiv.style.display = "none";
			}
			else {
				if (gadgets && gadgets.window) gadgets.window.setTitle("Task Management - Admin");
				adminDiv.style.display = "none";
				taskDiv.style.display = "inherit";
			}
			if (gadgets && gadgets.window && gadgets.window.adjustHeight) gadgets.window.adjustHeight();
		}
	}
	
	function updateUserList() {
	// function responsible for updating "assigned to" list after participants change

		// Checking for new participants
		//var participants = wave.getParticipants();
		//if (participants) {
		//	for (var i = 0; i < participants.length; ++i) {
		//		if (!partList[participants[i].getId()]) {
		//			partList[participants[i].getId()] = participants[i].getDisplayName();
		//			addParticipant(participants[i].getId());
		//		}
		//	}
		//

		// Checking for deleted participants
		//	for (part in partList) {
		//		if (!wave.getParticipantById(part) && !extraPartList[part]) {
		//			partList[part] = NULL;
		//		}
		//	}
		//}
	}
	
	function updateState() {
	// function responsible for updating the state
		
		loadParticipants();
		loadTasks();

	}
	
	function init() {
	// Function responsible for the initial gadget loading
	
		if (wave && wave.isInWaveContainer())
		{
			wave.setStateCallback(updateState);
			//wave.setParticipantCallback(updateUserList);
			//wave.setModeCallback(changeMode);
		}
	}
	
	gadgets.util.registerOnLoadHandler( init );